[Chapter Nineteen][Previous]
[Next] [Art of
Assembly][Randall Hyde]
Art of Assembly: Chapter Nineteen
- 19.3.2 - 32-bit Coroutines
19.3.2 32-bit Coroutines
The existing Standard Library (v1.0) coroutine package is not suitable for
programs that use the 80386 and later 32 bit register sets. As mentioned
earlier, the problem lies in the fact that the Standard Library only preserves
the 16-bit registers when switching between processes. However, it is a
relatively trivial extension to modify the Standard Library so that it saves
32 bit registers. To do so, just change the definition of the pcb
(to make room for the 32 bit registers) and the sl_cocall
routine:
.386
option segment:use16
dseg segment para public 'data'
wp equ <word ptr>
; 32-bit PCB. Note we only keep the L.O. 16 bits of SP since we are
; operating in real mode.
pcb32 struc
regsp word ?
regss word ?
regip word ?
regcs word ?
regeax dword ?
regebx dword ?
regecx dword ?
regedx dword ?
regesi dword ?
regedi dword ?
regebp dword ?
regds word ?
reges word ?
regflags dword ?
pcb32 ends
DefaultPCB pcb32 <>
DefaultCortn pcb32 <>
CurCoroutine dd DefaultCortn ;Points at the currently executing
; coroutine.
dseg ends
cseg segment para public 'slcode'
;============================================================================
;
; Coroutine support.
;
; COINIT- ES:DI contains the address of the current (default) process.
CoInit32 proc far
assume ds:dseg
push ax
push ds
mov ax, dseg
mov ds, ax
mov wp dseg:CurCoroutine, di
mov wp dseg:CurCoroutine+2, es
pop ds
pop ax
ret
CoInit32 endp
; COCALL32- transfers control to a coroutine. ES:DI contains the address
; of the PCB. This routine transfers control to that coroutine and then
; returns a pointer to the caller's PCB in ES:DI.
cocall32 proc far
assume ds:dseg
pushfd
push ds
push es ;Save these for later
push edi
push eax
mov ax, dseg
mov ds, ax
cli ;Critical region ahead.
; Save the current process' state:
les di, dseg:CurCoroutine
pop es:[di].pcb32.regeax
mov es:[di].pcb32.regebx, ebx
mov es:[di].pcb32.regecx, ecx
mov es:[di].pcb32.regedx, edx
mov es:[di].pcb32.regesi, esi
pop es:[di].pcb32.regedi
mov es:[di].pcb32.regebp, ebp
pop es:[di].pcb32.reges
pop es:[di].pcb32.regds
pop es:[di].pcb32.regflags
pop es:[di].pcb32.regip
pop es:[di].pcb32.regcs
mov es:[di].pcb32.regsp, sp
mov es:[di].pcb32.regss, ss
mov bx, es ;Save so we can return in
mov ecx, edi ; ES:DI later.
mov edx, es:[di].pcb32.regedi
mov es, es:[di].pcb32.reges
mov di, dx ;Point es:di at new PCB
mov wp dseg:CurCoroutine, di
mov wp dseg:CurCoroutine+2, es
mov es:[di].pcb32.regedi, ecx ;The ES:DI return values.
mov es:[di].pcb32.reges, bx
; Okay, switch to the new process:
mov ss, es:[di].pcb32.regss
mov sp, es:[di].pcb32.regsp
mov eax, es:[di].pcb32.regeax
mov ebx, es:[di].pcb32.regebx
mov ecx, es:[di].pcb32.regecx
mov edx, es:[di].pcb32.regedx
mov esi, es:[di].pcb32.regesi
mov ebp, es:[di].pcb32.regebp
mov ds, es:[di].pcb32.regds
push es:[di].pcb32.regflags
push es:[di].pcb32.regcs
push es:[di].pcb32.regip
push es:[di].pcb32.regedi
mov es, es:[di].pcb32.reges
pop edi
iret
cocall32 endp
; CoCall32l works just like cocall above, except the address of the pcb
; follows the call in the code stream rather than being passed in ES:DI.
; Note: this code does *not* return the caller's PCB address in ES:DI.
;
cocall32l proc far
assume ds:dseg
push ebp
mov bp, sp
pushfd
push ds
push es
push edi
push eax
mov ax, dseg
mov ds, ax
cli ;Critical region ahead.
; Save the current process' state:
les di, dseg:CurCoroutine
pop es:[di].pcb32.regeax
mov es:[di].pcb32.regebx, ebx
mov es:[di].pcb32.regecx, ecx
mov es:[di].pcb32.regedx, edx
mov es:[di].pcb32.regesi, esi
pop es:[di].pcb32.regedi
pop es:[di].pcb32.reges
pop es:[di].pcb32.regds
pop es:[di].pcb32.regflags
pop es:[di].pcb32.regebp
pop es:[di].pcb32.regip
pop es:[di].pcb32.regcs
mov es:[di].pcb32.regsp, sp
mov es:[di].pcb32.regss, ss
mov dx, es:[di].pcb32.regip ;Get return address (ptr to
mov cx, es:[di].pcb32.regcs ; PCB address.
add es:[di].pcb32.regip, 4 ;Skip ptr on return.
mov es, cx ;Get the ptr to the new pcb
mov di, dx ; address, then fetch the
les di, es:[di] ; pcb val.
mov wp dseg:CurCoroutine, di
mov wp dseg:CurCoroutine+2, es
; Okay, switch to the new process:
mov ss, es:[di].pcb32.regss
mov sp, es:[di].pcb32.regsp
mov eax, es:[di].pcb32.regeax
mov ebx, es:[di].pcb32.regebx
mov ecx, es:[di].pcb32.regecx
mov edx, es:[di].pcb32.regedx
mov esi, es:[di].pcb32.regesi
mov ebp, es:[di].pcb32.regebp
mov ds, es:[di].pcb32.regds
push es:[di].pcb32.regflags
push es:[di].pcb32.regcs
push es:[di].pcb32.regip
push es:[di].pcb32.regedi
mov es, es:[di].pcb32.reges
pop edi
iret
cocall32l endp
cseg ends
end
- 19.3.2 - 32-bit Coroutines
Art of Assembly: Chapter Nineteen - 29 SEP 1996
[Chapter Nineteen][Previous]
[Next] [Art of
Assembly][Randall Hyde]